﻿using System.Collections.Generic;
using System.Reflection;

namespace ChivalryUnity.Mvc
{
    public class MvcMediator
    {
        private List<MvcListenerToken> m_listeners;

        public MvcMediator()
        {
            m_listeners = new List<MvcListenerToken>();
        }

        internal void Init(MvcView view)
        {
            BindFields(view);
            BindProperties(view);
            BindListeners();
            OnInit();
        }
        protected virtual void OnInit() { }

        internal void Destroy()
        {
            UnbindListeners();
            OnDestroy();
        }

        protected virtual void OnDestroy() { }

        private void BindFields(MvcView view)
        {
            FieldInfo[] fields = GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            for (int i = 0; i < fields.Length; i++)
            {
                FieldInfo field = fields[i];
                if (!field.IsDefined(typeof(MvcBindAttribute), false))
                    continue;

                if (field.FieldType == view.GetType())
                {
                    field.SetValue(this, view);
                }
                if (field.FieldType.IsSubclassOf(typeof(MvcContext)))
                {
                    MvcContext context = MvcFacade.Instance.RetriveContext(field.FieldType);
                    field.SetValue(this, context);
                }
            }
        }

        private void BindProperties(MvcView view)
        {
            PropertyInfo[] properties = GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            for (int i = 0; i < properties.Length; i++)
            {
                PropertyInfo property = properties[i];
                if (!property.IsDefined(typeof(MvcBindAttribute), false))
                    continue;

                if (property.PropertyType == view.GetType())
                {
                    property.SetValue(this, view, null);
                }
                if (property.PropertyType.IsSubclassOf(typeof(MvcContext)))
                {
                    MvcContext context = MvcFacade.Instance.RetriveContext(property.PropertyType);
                    property.SetValue(this, context, null);
                }
            }
        }

        private void BindListeners()
        {
            MethodInfo[] methods = GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            for (int i = 0; i < methods.Length; i++)
            {
                MethodInfo method = methods[i];
                object[] attrs = method.GetCustomAttributes(typeof(MvcBindAttribute), false);
                if (attrs.Length > 0)
                {
                    MvcBindAttribute attr = attrs[0] as MvcBindAttribute;
                    if (string.IsNullOrEmpty(attr.MsgKey))
                        continue;

                    MvcListenerToken token = MvcFacade.Instance.AddListener(attr.MsgKey, this, method);
                    m_listeners.Add(token);
                }
            }
        }

        private void UnbindListeners()
        {
            foreach (var token in m_listeners)
            {
                MvcFacade.Instance.RemoveListener(token);
            }
            m_listeners.Clear();
        }
    }
}